 1.扩展部分之类型参数
   
   扩展部分主要内容：
       1).类型参数
          泛型类、泛型函数、协变和逆变
       2).Akka
   
   Scala的类型参数与Java的泛型是一样的，可以在集合、类、函数中定义类型参数，从而保证程序更好的
健壮性。
   
   1).泛型类
   泛型类，顾名思义，其实就是在类的声明中定义一些泛型类型，然后在类内部的字段或者方法，就可以
使用这些泛型类型。
   使用泛型类，通常是需要对类中的某些成员，比如某些字段和方法中的参数或变量进行统一的类型限
制，这样可以保证程序更好的健壮性和稳定性。
   如果不使用泛型进行统一的类型限制，那么在后期程序运行过程中难免会出现问题，比如传入了不希望
的类型导致程序出问题。
   在使用泛型类的时候，比如创建泛型类的对象，只需将类型参数替换为实际的类型即可。
   Scala自动推断泛型类型特性：直接给使用泛型类型的字段赋值时，Scala会自动进行类型推断。
   泛型类的定义如下：

//定义一个泛型类
class Stack[T1, T2, T3](name: T1) {
  var age: T2 = _
  var address: T3 = _

  def getInfo: Unit = {
  println(s"$name,$age,$address")
  }
}
   使用上述的泛型类，只需要使用具体的类型代替类型参数即可。
   
object GenericityDemo {
  def main(args: Array[String]): Unit = {
    //创建泛型类对象
    val stack = new Stack[String, Int, String]("lisi")
    stack.age = 20
    stack.address = "北京"

	stack.getInfo
  }
}
   2).泛型函数
   泛型函数，与泛型类类似，可以给某个函数在声明时指定泛型类型，然后在函数体内，多个变量或者返
回值之间，就可以使用泛型类型进行声明，从而对某个特殊的变量，或者多个变量，进行强制性的类型
限制。
   
   与泛型类一样，你可以通过给使用了泛型类型的变量传递值来让Scala自动推断泛型的实际类型，也可
以在调用函数时，手动指定泛型类型。

   案例：卡片售卖机，可以指定卡片的内容，内容可以是String类型或Int类型
   
object GenericityFunction {
  def getCard[T](content: T) = {
    content match {
      case content: Int => s"card:$content is Int "
      case content: String => s"card:$content is String"
      case _ => s"card:$content"
    }
  }

  def main(args: Array[String]): Unit = {
    println(getCard[String]("hello"))
    println(getCard(1001))
  }
}
   3).协变与逆变
   Scala的协变和逆变是非常有特色的，完全解决了Java中的泛型的一大缺憾！
   举例来说，Java中，如果有Professional是Master的子类，那么Card[Professionnal]是不是
Card[Master]的子类？答案是：不是。因此对于开发程序造成了很多的麻烦。
   
   而Scala中，只要灵活使用协变和逆变，就可以解决Java泛型的问题。
   协变定义形式如：trait List[+T] {}
   
   当类型S是类型A的子类型时，则List[S]也可以认为是List[A}的子类型，即List[S]可以泛化为List[A]，也
就是被参数化，类型的泛化方向与参数类型的方向是一致的，所以称为协变（covariance）。
   
   逆变定义形式如：trait List[-T] {}
   当类型S是类型A的子类型，则Queue[A]反过来可以认为是Queue[S}的子类型，也就是被参数化类型的
泛化方向与参数类型的方向是相反的，所以称为逆变（contravariance）。

   小结：
        如果A是B的子类，那么在协变中，List[A]就是List[B]的子类； 在逆变中，List[A]就是List[B]
的父类。

   协变案例：只有大师以及大师级别以下的名片都可以进入会场
   
package lagou.cn.part11

//大师
class Master

//专家
class Professor extends Master

//讲师
class Teacher

//这个是协变，Professor是Master的子类，此时Card[Profesor]也是Card[Master]的子类
class Card[+T]

object CovarianceDemo {
	
  def enterMeet(card: Card[Master]): Unit = {
    //只有Card[Master]及其子类Card[Professor]才能进入会场。
    println("欢迎进入会场！")
  }

  def main(args: Array[String]): Unit = {
    val masterCard = new Card[Master]
    val professorCard = new Card[Professor]
    val teacharCard = new Card[Teacher]

	enterMeet(masterCard)
    enterMeet(professorCard)
    //此处就会报错
    //enterMeet(teacharCard)
  }
}






package lagou.cn.part11

//大师
class Master
//专家
class Professor extends Master

//讲师
class Teacher

//定义协变
//class Card[+T]

//定义逆变
class Card[-T]
object CovarianceDemo2 {
  def enterMeet(card: Card[Professor]):Unit={
    //只有Card[Master]和它的子类才能进入会场、
    println("欢迎进入会场")
  }
  def main(args: Array[String]): Unit = {
    val masterCard = new Card[Master]
    val professorCard = new Card[Professor]
    val teacherCard = new Card[Teacher]

    enterMeet(masterCard)
    enterMeet(professorCard)
//    enterMeet(teacherCard)

  }

}

 2.Akka
   
   Akka是Java虚拟机平台上构建高并发、分布式和容错应用的工具包和运行时。
   Akka用Scala语言编写，同时提供了Scala和Java的开发接口。
   Akka处理并发的方法基于Actor模型，Actor之间通信的唯一机制就是消息传递。
   
   Actor
   Scala的Actor类似于Java中的多线程编程。
   但是不同的是，Scala的Actor提供的模型与多线程有所不同。Scala的Actor尽可能地避免锁和共享状
态，从而避免多线程并发时出现资源争用的情况，进而提升多线程编程的性能。
   
   Actor可以看作是一个个独立的实体，Actor之间可以通过交换消息的方式进行通信，每个Actor都有自
己的收件箱（Mailbox）。
   
   一个Actor收到其他Actor的信息后，根据需要作出各种相应。消息的类型可以是任意的，消息的内容也
可以是任意的。
   
   ActorSystem
   在Akka中，ActorSystem是一个重量级的结构。

   它需要分配多个线程，所以在实际应用中，ActorSystem通常是一个单例对象，我们可以使用这个
ActorSystem创建很多Actor。
   
   Akka案例：
   创建一个maven项目，在项目的pom文件中增加如下依赖：

<!-- 定义一下常量-->
<properties>
    <encoding>UTF-8</encoding>
    <scala.version>2.12.3</scala.version>
    <scala.compat.version>2.11</scala.compat.version>
    <akka.version>2.4.17</akka.version>
</properties>

<dependencies>
    <!-- 添加akka的actor依赖 -->
    <dependency>
        <groupId>org.scala-lang</groupId>
        <artifactId>scala-actors</artifactId>
        <version>2.11.8</version>
    </dependency>

	<!-- https://mvnrepository.com/artifact/com.typesafe.akka/akka-actor -->
    <dependency>
        <groupId>com.typesafe.akka</groupId>
        <artifactId>akka-actor_2.11</artifactId>
        <version>2.3.16</version>
    </dependency>
	
	<!-- 添加akka的actor依赖 -->
    <dependency>
        <groupId>com.typesafe.akka</groupId>
        <artifactId>akka-actor_${scala.compat.version}</artifactId>
        <version>${akka.version}</version>
    </dependency>

	<!-- 多进程之间的Actor通信 -->
    <!-- https://mvnrepository.com/artifact/com.typesafe.akka/akka-remote -->

	<dependency>
        <groupId>com.typesafe.akka</groupId>
        <artifactId>akka-remote_${scala.compat.version}</artifactId>
        <version>${akka.version}</version>
    </dependency>
	
</dependencies>


package cn.lagou.edu.scala.section4

import akka.actor.{Actor, ActorSystem, Props}

import scala.io.StdIn

class HelloActor extends Actor {
  // 接收消息并处理
  override def receive: Receive = {
    case "吃了吗" => println("吃过了")
    case "吃的啥" => println("北京卤煮")
    case "拜拜" => {
      //关闭自己
      context.stop(self)
      //关闭ActorSystem
      context.system.terminate()
    }
  }
}

object HelloActor {
  //创建线程池对象MyFactor，myFactory为线程池的名称
  private val MyFactory = ActorSystem("myFactory")

  // 通过MyFactory.actorOf方法来创建一个actor；
  // 第一个参数传递自定义的HelloActor类，第二个参数是给actor起个名字
  private val helloActorRef = MyFactory.actorOf(Props[HelloActor], "helloActor")

  def main(args: Array[String]): Unit = {
    var flag = true
    while (flag) {
      print("请输入想发送的消息：")
      val consoleLine: String = StdIn.readLine()
      //通过！来发送消息
      helloActorRef ! consoleLine
      if (consoleLine.equals("拜拜")) {
	    flag = false
        println("程序即将结束！")
      }

	  // 休眠100毫秒
      Thread.sleep(100)
    }
  }
}

  《Scala编程》本课程共十一部分
   课程目的：使用Scala进行Spark开发、阅读Spark源码
   第一部分 Scala基础
   第二部分 控制结构和函数
   第三部分 数组和元组
   第四部分 类与对象
   第五部分 继承
   第六部分 特质
   第七部分 模式匹配和样例类
   第八部分 函数及抽象化
   第九部分 集合
   第十部分 隐式机制
   第十一部分 扩展部分
   Scala功能强大，内容很多，还有一些内容课程中没有涉及
   这门课程作为大家学习Scala的起点，而非终点
